﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Reflection;
using System.Threading;

namespace Icedream.InstantFileTransfer
{
    public class IIFTPPluginInterface
    {
        public List<IFTPStreamPlugin> _streamPlugins = new List<IFTPStreamPlugin>();

        /// <summary>
        /// Gets all stream plugins currently loaded
        /// </summary>
        public IFTPStreamPlugin[] LoadedStreamPlugins
        {
            get { return _streamPlugins.ToArray(); }
        }

        /// <summary>
        /// Gets all names of the stream plugins currently loaded
        /// </summary>
        public string[] LoadedStreamPluginNames
        {
            get
            {
                string[] a = new string[_streamPlugins.Count];
                int i = -1;
                foreach (IFTPStreamPlugin p in _streamPlugins)
                {
                    a[++i] = p.CompressionName != null ? p.CompressionName : p.CompressionString;
                }
                return a;
            }
        }

        #region Plugin functions
        public void LoadPlugin(IFTPStreamPlugin plugin)
        {
            if (plugin.CanCompress || plugin.CanDecompress)
                _streamPlugins.Add(plugin);
            else
                throw new TypeLoadException("Plugin is not able to compress and decompress files. To be valid, the plugin must be able to compress and/or to decompress files.");
        }

        public void LoadPlugin(string dllPath)
        {
            if (!File.Exists(dllPath))
                throw new FileNotFoundException("Plugin DLL not found", dllPath);

            Assembly dll;

            try
            {
                dll = Assembly.LoadFile(dllPath);

#if PLUGINS_FULLYTRUSTEDONLY
                if(!dll.IsFullyTrusted)
                    throw new FileLoadException("DLL is not a fully trusted plugin");
#endif

                Type[] exportedTypes = dll.GetExportedTypes();

                bool hasPlugins = false;

                foreach (Type type in exportedTypes)
                {
                    if (type.IsSubclassOf(typeof(IFTPStreamPlugin)))
                    {
                        try
                        {
                            IFTPStreamPlugin activatedInstance = (IFTPStreamPlugin)Activator.CreateInstance(type);
                            if(InternalPluginLoaded != null)
                                InternalPluginLoaded(activatedInstance);
                            LoadPlugin(activatedInstance);
                            if (!hasPlugins)
                                hasPlugins = true;
                        }
                        catch (Exception e)
                        {
                            throw new FileLoadException("Plugin DLL could not be loaded", e);
                        }
                    }
                }

                if (!hasPlugins)
                    throw new FileLoadException("DLL does not contain a valid plugin");
            }
            catch (FileLoadException e)
            {
                throw new FileLoadException("DLL is not a valid plugin", e);
            }
        }

        internal event InternalPluginLoadedHandler InternalPluginLoaded;
        #endregion
    }

    delegate void InternalPluginLoadedHandler(IFTPStreamPlugin plugin);
}
